/*
 * Common javascript utils.	
 *	
 * @author Jetty (yangjian505@gmail.com)	
 */	

function Yutil() {
}

Yutil.isIE = document.all && !/Opera/i.test(navigator.userAgent);

Yutil.isIE6 = Yutil.isIE && navigator.appName == 'Microsoft Internet Explorer' && parseFloat(/MSIE ([0-9]{1,}[\.0-9]{0,})/.exec(navigator.userAgent)[1]) < 7.0

// checks whether the given key event prepresents a char
Yutil.isChar = function(e) {
	if (e.ctrlKey || e.altKey) return false;
	if (e.charCode) return true;
	var k = e.keyCode;
	return k==32 || (k>=65 && k<=90) || (k>=48 && k<=57)
		|| (k>=186 && k<=192) || (k>=219 && k<=222);
}

// returns the given key event's char code
Yutil.charCode = function(e) {
	if (!Yutil.isChar(e)) return 0;
	if (e.charCode) return e.charCode;
	var k = e.keyCode;
	var s = e.shiftKey;
	var c = '';
	if (k>=65 && k<=90) return s ? k : k + 32;
	switch (k) {
		case 32: c = ' '; break;
		case 48: c = s ? ')' : '0'; break;
		case 49: c = s ? '!' : '1'; break;
		case 50: c = s ? '@' : '2'; break;
		case 51: c = s ? '#' : '3'; break;
		case 52: c = s ? '$' : '4'; break;
		case 53: c = s ? '%' : '5'; break;
		case 54: c = s ? '^' : '6'; break;
		case 55: c = s ? '&' : '7'; break;
		case 56: c = s ? '*' : '8'; break;
		case 57: c = s ? '(' : '9'; break;
		case 186: c = s ? ':' : ';'; break;
		case 187: c = s ? '+' : '='; break;
		case 188: c = s ? '<' : ','; break;
		case 189: c = s ? '_' : '-'; break;
		case 190: c = s ? '>' : '.'; break;
		case 191: c = s ? '?' : '/'; break;
		case 192: c = s ? '~' : '`'; break;
		case 219: c = s ? '{' : '['; break;
		case 220: c = s ? '|' : '\\'; break;
		case 221: c = s ? '}' : ']'; break;
		case 222: c = s ? '"' : "'"; break;
	}
	return c.length > 0 ? c.charCodeAt(0) : 0;
}

Yutil.isArray =	function(data) {
	return data.join ? true	: false;
}

Yutil.isDate = function(data) {
	return data.toUTCString	? true : false;	
}

Yutil.callOnLoad = function(load) {
	if (window.addEventListener) {
		window.addEventListener("load",	load, false);
	} else if (window.attachEvent) {
		window.attachEvent("onload", load);	
	} else {
		window.onload =	load;
	}
}

Yutil.isLineal = function(parent, child) {
	while (parent != child && child != null)
		child = child.parentNode;
	return parent == child;
}

Yutil.currentFocus = function() {
	var focus = null;

	// IE's activeElement property
	if (document.activeElement)
	{
		focus = document.activeElement;
	}
	// W3 selection method. Currently only Mozilla & Safari support it.
	else if (window.getSelection)
	{
		var theSelection = window.getSelection();

		// The Safari way to get the node that a selection starts in
		if (theSelection.baseNode)
		{
			focus = theSelection.baseNode;
		}
		// The Mozilla way to get the node that a selection starts in
		else if (theSelection.getRangeAt && theSelection.rangeCount > 0)
		{
			focus = theSelection.getRangeAt(0).startContainer;
		}
	}
	
	return focus;
}

Yutil.ensureId = function(e) {
	if (!e.id) {
		var i = new Date().getTime() % 1000000;
		while ($(i.toString())) i += 169;
		e.setAttribute('id', e.id = i.toString());
	}
	return e.id;
}

Yutil.remoteCallInfo = function(e) {
	while (e != null && e.rcinfo == null)
		e = e.parentNode;
	return e ? e.rcinfo : null;
}

/**
* By default, changeDetection is enabled
*/
Yutil.remoteCall = function(src, url, targetId, dontBlock) {	
	Yutil.remoteCall(src, url, targetId, dontBlock, true);
}

Yutil.remoteCall = function(src, url, targetId, dontBlock, enableChgDetect) {	
	src = $(src);
	target = $(targetId);
	
	if (!target) {
		alert("target cannot be null, id is:"+ targetId);
	}

	//Detect changes
	if(enableChgDetect && !Yutil.chgDetect(targetId)){
		return;
	}

	var	query =	"_targetDivId=" + target.id + "&";
	if (src) {
		query += Form.serialize(src);
	}
	
	var myAjax = new Ajax.Request(
		url, 
		{
			method: 'post',
			parameters: query,
			targetId: target.id,
			block: dontBlock ? false : true
		});
}

Yutil.remoteCallHandler = {
	onCreate: function(ajaxReq, transport, json) {
	},
	
	onComplete: function(ajaxReq, transport, json) {
		var resp = transport.responseText;
		var tmp;
		
		// check error indicated by "[error_message]"
		if ((tmp = resp.indexOf("[error_message]")) >= 0) {
		
			showError(resp.substring(tmp + 15));
			return;
		}
		
		// check error indicated by status code
		if (!ajaxReq.responseIsSuccess()) {
			if (ajaxReq.options.block) // keep async requests silent
				alert("Failed to connect DWC backend, maybe DWC has exited already. Please restart and try again.");
			return;
		}

		// successful response
		var targetId = ajaxReq.options.targetId;
		if (resp.substring(0, 1) == "[") {
			if ((tmp = resp.indexOf("]")) > 0) {
				targetId = resp.substring(1, tmp);
				resp = resp.substring(tmp + 1);
			}
		}
		
		if (targetId == "js") {
			eval(resp); // javascript response
		} else {
//var start = new Date().getTime();

			var	dest = $(targetId);

			// script off self-nesting element, if any
			resp = Yutil.stripRootElement(resp, targetId);
			
			// de-enhance the content going to be replaced
			Yutil.en.deenhance(dest);
			
//alert("before, " + (new Date().getTime() - start));
//start = new Date().getTime();

			// replace dest with response
			dest.innerHTML = resp;
			dest.rcinfo = {url:ajaxReq.url, target:dest, timestamp:new Date()};
			
//alert("update DOM, " + (new Date().getTime() - start));
//start = new Date().getTime();

			// enhance the new content
			if (window.Yfit) Yfit.makeFit(dest);
			Yutil.en.enhance(dest);
			
//alert("enhance, " + (new Date().getTime() - start));
//start = new Date().getTime();

			// evaluate	javascripts	in the response
			resp.evalScripts();

//alert("page JS, " + (new Date().getTime() - start));
//start = new Date().getTime();
			
			// force IE redraw to walk-around an IE6 bug
			if (Yutil.isIE6 && Element.getStyle(dest, 'display') == 'block') {
				dest.style.display = 'none';
				setTimeout(function() {
					dest.style.display = 'block';					
					if (window.Yfit) Yfit.makeFit(dest);
				}, 1);
			}
			else
				if (window.Yfit) Yfit.makeFit(dest);
		}
	},
	
	onException: function(ajaxReq, exception) {
		if (ajaxReq.options.block) // keep async requests silent
			alert("Failed to connect DWC backend, maybe DWC has exited already. Please restart and try again.");
	}
};
Ajax.Responders.register(Yutil.remoteCallHandler);

Yutil.stripRootElement = function(html, rootElemId) {
	var idOccur1 = html.indexOf("id='"+rootElemId+"'");
	var idOccur2 = html.indexOf('id="'+rootElemId+'"');
	var idOccur = idOccur1 < 0 ? idOccur2 : idOccur1;
	if (idOccur >= 0) {
		// found root element, remove it from html
		var begin = html.indexOf(">");
		var end = html.lastIndexOf("<");
		if (begin > idOccur && end > idOccur) {
			return html.substring(begin + 1, end);
		}
	}
	// didn't find specified root element, return unchanged
	return html;
}

/**
 * Setup a GMail style loading message
 */	
Yutil.useLoadingMessage	= function()
{
	//description on Ajax.Responders
	//Ajax.Responders对象维护了一个正在运行的Ajax对象列表，在需要实现一些全局的功能时使用。
	//在Ajax请求发出以后提示用户操作正在执行
	//当操作返回以后取消提示
	Ajax.Responders.register({
		blockCount: 0,
		
		onCreate: function(ajaxReq) {
				this.blockCount++;
				if (this.blockCount >= 0)
					Yutil.showDisabledZone(null, 1000, 'Loading...');
		},

		onComplete: function(ajaxReq) {
				this.blockCount--;
				if (this.blockCount <= 0)
					Yutil.hideDisabledZone(null, 1000);
		}
	});
}

Yutil.showDisabledZone = function(e, zidx, msg, fog) {
	e = $(e) || document.body;
	zidx = zidx || 1000;
	msg = msg || '';
	if (!e.id) { 
		alert(e + ' need an id'); 
		return; 
	}
	var d = $(e.id+'_disabledZone'+zidx);
	//alert(d);
	if (!d) {
		d = ("<div id='"+e.id+"_disabledZone"+zidx+"' style='position:absolute; "+(fog ? "background:gray; opacity:.30; filter:alpha(opacity=30);" : "background:white; opacity:.01; filter:alpha(opacity=01);")+"'></div>").createElement();
		(e.offsetParent || e).appendChild(d);
	}
	var m = $(e.id+'_loadingMessage'+zidx);
	if (!m) {
		m = ("<div id='"+e.id+"_loadingMessage"+zidx+"' style='position:absolute; color:white; background:red; padding:5px;'></div>").createElement();
		(e.offsetParent || e).appendChild(m);
	}
	d.style.zIndex = zidx;
	m.style.zIndex = zidx + 1;
	m.innerHTML = msg;

	Yutil.moveTo(d, e.offsetLeft, e.offsetTop);
	Yutil.moveTo(m, e.offsetLeft, e.offsetTop);
	if (e == document.body)
		d.style.width = d.style.height = '100%';
	else
		Yutil.resizeTo(d, e.offsetWidth, e.offsetHeight);
	
	d.style.display = 'block';
	if (msg) {
		m.style.display = 'block';
		m.style.width = 'auto';
	} else
		m.style.display = 'none';
}

Yutil.hideDisabledZone = function(e, zidx) {
	e = $(e) || document.body;
	zidx = zidx || 1000;
	var d = $(e.id+'_disabledZone'+zidx);
	var m = $(e.id+'_loadingMessage'+zidx);
	if (m) {
		m.style.display = 'none';
	}
	if (d) {
		d.style.display = 'none';
	}
}

Yutil.createDialog = function(id, width, height, title, entityC2id, entityName, maxEntityNameLen ) {
	// Compose dialog title, title - entityC2id(entityName)
	title = title || "";
	if ( null != entityC2id && undefined != typeof( entityC2id ) ){
		title += ( " - " + "<span class='smaller'>" + entityC2id );
		if ( null != entityName && undefined != typeof( entityName ) ){
			if ( null == maxEntityNameLen || undefined == typeof( maxEntityNameLen ) )
				maxEntityNameLen = 20;
			
			if ( entityName.length > maxEntityNameLen ) {
				entityName = entityName.substr( 0, maxEntityNameLen ) + "...";
			}
			title += "(" + entityName + ")";
		}
		title += "</span>";
	}
	
	var d = $(id);
	if (!d) {
		d = (
			"<div id='"+id+"' class='dialog' style='visibility:hidden; width:"+width+"; height:"+height+";' onkeypress='if(27==event.keyCode)Yutil.hideDialog(this);' tabindex='-1'>"+
				"<h1>"+
					"<div class='dialog_close' onclick='Yutil.hideDialog(this.parentNode.parentNode)'></div>"+
					"<span id='"+id+"_title'>"+title+"</span>"+
				"</h1>"+
				"<div id='"+id+"_content' class='dialog_content'></div>"+
				"<!--[if lte IE 6.5]><iframe frameborder='0' style='position:absolute; z-index:-1; left:0; top:0; width:100%; height:100%;'></iframe><![endif]-->"+
			"</div>").createElement();
		document.body.appendChild(d);
		var con = $(id+'_content');
		con.autoResize = Yutil._resizeDialogContent;
		con.autoResize();
		if (Ydragdrop)
			Ydragdrop.enhanceDragable(d.firstChild, d);
	}
	return d;
}

Yutil._resizeDialogContent = function() {
	var content = this, p = this.parentNode;
	content.style.height = (p.offsetHeight-2-16-10-p.firstChild.offsetHeight)  + 'px';
}

Yutil.setDialogTitle = function(id, title) {
	var d = $(id);
	$(d.id+'_title').innerHTML = title;
}

Yutil.disposeDialog = function(id) {
	var d = $(id);
	if (d) {
		d.parentNode.removeChild(d);
		delete d;
	}
}

Yutil.shownDialogs = {};

Yutil.showDialog = function(d, zidx, x, y) {
	d = $(d);

	zidx = zidx || 0;
	if (!zidx) {
		zidx = 100;
		for (diagId in Yutil.shownDialogs)
			zidx = Math.max(zidx, Yutil.shownDialogs[diagId] + 100);
	}

	var win = Yutil.winSize();
	if (x == null) x = (win[0] - d.offsetWidth) / 2;
	if (y == null) y = (win[1] - d.offsetHeight) / 2;

	Yutil.showDisabledZone(null, zidx-1, '', true);
	d.zIndexDZ = zidx-1;
	d.style.zIndex = zidx;
	d.style.visibility = 'visible';
	Yutil.moveTo(d, x, -d.offsetHeight);
	Yutil.shownDialogs[d.id] = zidx;
	
	d.focus();
	d.ani = new Tween(d.style, 'top', Tween.regularEaseOut, -d.offsetHeight, y, .3, 'px');
	d.ani.start();
}

Yutil.hideDialog = function(d) {
	d = $(d);
	delete Yutil.shownDialogs[d.id];
	if (!d || d.style.visibility == 'hidden') return;
	d.ani.onMotionFinished = function() {
		d.style.visibility = 'hidden';
		Yutil.hideDisabledZone(null, d.zIndexDZ);
	};
	d.ani.continueTo(-d.offsetHeight, .2);
}

Yutil.show = function(elem, style) {
	Yutil.display(elem, true, style);
}

Yutil.hide = function(elem) {
	Yutil.display(elem, false);
}

//Show a hide elem in table
Yutil.showInTable = function(elem){
	$(elem).style.display = '';	
}

Yutil.toggleDisplay = function(elem, style) {
	elem = $(elem);
	Yutil.display(elem, elem.style.display == 'none', style);
}

Yutil.display = function(elem, show, style) {
	elem = $(elem);
	if (elem)
		elem.style.display = show ? (style || 'block') : 'none';
}

Yutil.winSize = function() {
	var winWidth = window.innerWidth || document.documentElement.clientWidth;
	var winHeight = window.innerHeight || document.documentElement.clientHeight;
	return [winWidth, winHeight];
}

Yutil.distance = function(x1, y1, x2, y2) {
	return Math.sqrt(Math.pow(x1-x2, 2) + Math.pow(y1-y2, 2));
}

Yutil.pos = function(elem) {
	elem = $(elem);
	var x = parseInt(elem.style.left);
	var y = parseInt(elem.style.top);
	return [isNaN(x) ? 0 : x, isNaN(y) ? 0 : y];
}

Yutil.abspos = function(elemOrId) {
	var e = $(elemOrId);
	var off = Position.realOffset(e);
	var cum = Position.cumulativeOffset(e);

	// special case: scrollTop (realOffset) of <select> is the scroll position
	// of the inner dropdown; should be minus-ed
	if ("select".isTagOf(e)) off[1] -= e.scrollTop || 0;

	return [cum[0] - off[0], cum[1] - off[1]];
}

Yutil.intersects = function(nwPosA, widthA, heightA, nwPosB, widthB, heightB) {
	return nwPosA[0]<=nwPosB[0]+widthB && nwPosA[0]+widthA>=nwPosB[0]
		&& nwPosA[1]<=nwPosB[1]+heightB && nwPosA[1]+heightA>=nwPosB[1];
}

Yutil.getLeft =	function(elemOrId) {
	var	elem = $(elemOrId);
	var	x =	0;
	while (elem) {
		if (elem.offsetLeft) {
			x += elem.offsetLeft;
		}
		elem = elem.offsetParent ? elem.offsetParent : null;
	}
	return x;
}

Yutil.getTop = function(elemOrId) {	
	var	elem = $(elemOrId);
	var	y =	0;
	while (elem) {
		if (elem.offsetTop)	{
			y += elem.offsetTop;
		}
		elem = elem.offsetParent ? elem.offsetParent : null;
	}
	return y;
}

Yutil.getWidth = function(elemOrId)	{
	var	elem = $(elemOrId);
	return elem.offsetWidth;
}

Yutil.getHeight	= function(elemOrId) {
	var	elem = $(elemOrId);
	return elem.offsetHeight;
}

Yutil.moveTo = function(elemOrId, x, y)	{
	var	elem = $(elemOrId);
	elem.style.left	= x	+ "px";	
	elem.style.top = y + "px";
}

Yutil.resizeTo = function(elemOrId,	w, h) {	
	var	elem = $(elemOrId);
	elem.style.width = w + "px";
	elem.style.height =	h +	"px";
}

Yutil.fitToParent = function(elemOrId, heightLeft) {
	var e = $(elemOrId);
	var p = e.parentNode;
	var ep = Yutil.abspos(e), pp = Yutil.abspos(p);
	var w = p.offsetWidth-(ep[0]-pp[0])-4, h = p.offsetHeight-(ep[1]-pp[1])-4;

	if (!heightLeft && e.getAttribute("heightLeft"))
		heightLeft = parseInt(e.getAttribute("heightLeft"));
	if (heightLeft)
		h -= heightLeft;

	if (e.tHead) {
		p.style.overflowY = 'hidden';
		p.style.overflowX = 'auto';
		Yutil.makeFixedTableHeader(e, h);
	} else {
		e.style.width = w + 'px';
		e.style.height = h + 'px';
		e.style.overflow = 'auto';
	}
}

Yutil.makeFixedTableHeader = function(tab, h) {
	if (!tab.tHead) return;
	
	// height is given;
	// width must be wide enough to show the whole table!
	var w = tab.offsetWidth;

	// make scrollable table with fixed header
	if (Yutil.isIE) {
		// IE solution
		var bodyWidth = w;
		tab.style.width = bodyWidth + 'px';
		w = w + Yutil.scrollBarSize(); // give space to scroll bar

		var headHeight = tab.tHead.offsetHeight;
		var bodyHeight = h - headHeight;
		
		var c1 = ("<div class='fixed_head_c1' style='padding-top:"+headHeight+"px;width:"+w+"px;height:"+bodyHeight+"px;'></div>").createElement();
		var c2 = ("<div class='fixed_head_c2'></div>").createElement();

		tab.parentNode.insertBefore(c1, tab);
		c1.appendChild(c2);
		c2.appendChild(tab);
	} else {
		// FF solution
		w = w + 20; // add width for scrollbar, 20 is fixed in css
		'scrollbarAtRight'.addClass(tab.tBodies[0]);

		h = h - tab.tHead.offsetHeight - 3;
		if (w > tab.parentNode.offsetWidth)
			h -= Yutil.scrollBarSize(); // leave height for h-scrollbar
		
		tab.style.width = w + 'px';
		tab.tBodies[0].style.height = h + 'px';
		tab.tBodies[0].style.overflowY = 'scroll';
		tab.tBodies[0].style.overflowX = 'hidden';
	}
}

Yutil.dockTo = function(elemOrId, target, dir) {
	var e = $(elemOrId), t = $(target);
	var p = Yutil.abspos(t);
	var win = Yutil.winSize();

	var ts = p[1] - document.body.scrollTop
	var bs = win[1] - ts - t.offsetHeight;
	if (!dir)
		dir = (bs > e.offsetHeight || bs > ts) ? 'bottom' : 'top';
	
	if (dir == 'top')
		Yutil.moveTo(e, p[0], p[1] - e.offsetHeight);
	else if (dir == 'bottom')
		Yutil.moveTo(e, p[0], p[1] + t.offsetHeight);
}

Yutil._scrollBarSize = 0;
Yutil.scrollBarSize = function() {
	if (!Yutil._scrollBarSize) {
		var t = "<div id='scroll_test' style='position:absolute;left:-1000px;top:-1000px;width:100px;height:100px;overflow:hidden;background:red;'><div id='scroll_test_in' style='width:200px;height:200px;background:blue;'>&nbsp;</div></div>".createElement();
		document.body.appendChild(t);
		var w1 = t.clientWidth;
		t.style.overflow = 'auto';
		var w2 = t.clientWidth;
		document.body.removeChild(t);
		Yutil._scrollBarSize = w1 - w2;
	}
	return Yutil._scrollBarSize;
}

Yutil.textNodes = function(elem, result) {
	if (result == null) result = [];
	if (elem.nodeType == 3) {
		result.push(elem);
		return result;
	}
	for (var i = 0; i < elem.childNodes.length; i++)
		Yutil.textNodes(elem.childNodes[i], result);
	return result;
}

Yutil.innerText = function(e) {
	if (typeof e == "string" || typeof e == "undefined") return e;
	if (e.innerText) return e.innerText;	// Not needed but it is faster
	var str = "";
	var texts = Yutil.textNodes(e);
	for (var i = 0; i < texts.length; i++)
		str += texts[i].data;
	return str;
}

Yutil.selectByValue = function(sel, value) {
	for (var i = 0; i < sel.options.length; i++)
		if (sel.options[i].value == value) {
			sel.selectedIndex = i;
			return;
		}
}

Yutil.fireEventOnEnter = function(form, target, eventName) {
	Event.observe(form, "keypress", function(event) {
		if (event.keyCode == 13 && !event.ctrlKey && !event.altKey) {
			target.fireEvent(eventName);
			Event.stop(event);
		}
	});
}

Yutil.classes = function(e) {
	e = $(e);
	return (e.className || '').splitExcludeBlank();
}

Yutil.en = {
	registry: new Object(),

	// register an Enhancement
	register: function(query, initFn, finalFn) {
		if (initFn == null) return;
		Yutil.en.registry[query] = [initFn, finalFn];
	},
	
	// enhance all nodes under the given root
	enhance: function(root) {
		root = root || document;

		var query, initFn, nodes, n, enDone;
		for (query in Yutil.en.registry) {
			initFn = Yutil.en.registry[query][0];
			nodes = jQuery.find(query, root);
			for (var i = 0; i < nodes.length; i++) {
				n = nodes[i];
				if (n.en == undefined) n.en = [];
				if (n.en.indexOf(initFn) == -1) {
					enDone = initFn(n);
					if (enDone != false) // so no return value means enhanced
						n.en.push(initFn);
				}
			}
		}

		// auto resize goes last
		Yutil.autoResize(null, root);
	},
	
	// de-enhance all nodes under the given root to release resources
	// (before the nodes are removed from DOM)
	deenhance: function(root) {
		root = root || document;
		
		var query, initFn, finalFn, nodes, n;
		for (query in Yutil.en.registry) {
			initFn = Yutil.en.registry[query][0];
			finalFn = Yutil.en.registry[query][1];
			nodes = jQuery.find(query, root);
			for (var i = 0; i < nodes.length; i++) {
				n = nodes[i];
				if (n.en && n.en.indexOf(initFn) != -1) {
					if (finalFn != null)
						finalFn(n);
					n.en.splice(n.en.indexOf(initFn), 1);
				}
			}
		}
	},
	
	// get enhanced elements under the given root
	getEnhanced: function(root) {
		root = root || document;
		var result = [];
		
		var query, initFn, nodes, n;
		for (query in Yutil.en.registry) {
			initFn = Yutil.en.registry[query][0];
			nodes = jQuery.find(query, root);
			for (var i = 0; i < nodes.length; i++) {
				n = nodes[i];
				if (n.en && n.en.indexOf(initFn) != -1) {
					if (result.indexOf(n) == -1)
						result.push(n);
				}
			}
		}
		return result;
	},
	
	// get a specific type of enhanced elements under the given root
	getEnhancedByFn: function(root, initFn) {
		root = root || document;
		var result = [];
		
		var query, nodes, n;
		for (query in Yutil.en.registry) {
			if (Yutil.en.registry[query][0] != initFn)
				continue;
			nodes = jQuery.find(query, root);
			for (var i = 0; i < nodes.length; i++) {
				n = nodes[i];
				if (n.en && n.en.indexOf(initFn) != -1) {
					if (result.indexOf(n) == -1)
						result.push(n);
				}
			}
		}
		return result;
	}
}
// special auto resize enhancement
Yutil.en.register("div[autoResizeHeight]", function(d) {
	var func = "";
	if (d.getAttribute("autoResize"))
		func += d.getAttribute("autoResize")+";";
	if (d.getAttribute("autoResizeHeight"))
		func += "this.style.height=("+d.getAttribute("autoResizeHeight")+")+'px';";
	if (d.getAttribute("autoResizeWidth"))
		func += "this.style.width=("+d.getAttribute("autoResizeWidth")+")+'px';";
	d.autoResize = eval("t = function() {"+func+"}");
});
Yutil.autoResize = function(evt, root) {
	// called on each enhancement & window resize
	var divs = (root || document).getElementsByTagName("div");
	for (var i = 0; i < divs.length; i++) {
		var d = divs[i];
		if (d.autoResize && d.autoResize.constructor === Function)
			d.autoResize();
	}
}
Yutil.callOnLoad(function() {
	Yutil.en.enhance();
	Event.observe(window, "resize", Yutil.autoResize);
});

Yutil.en.register("acronym", function(trigger) {
	Event.observe(trigger, "mouseover", function() {
		"hover".addClass(trigger);
	});
	Event.observe(trigger, "mouseout", function() {
		"hover".removeClass(trigger);
	});
	Event.observe(trigger, "click", function() {
		if ("click".hasClass(trigger))
			"click".removeClass(trigger);
		else
			"click".addClass(trigger);
	});
});

Yutil.en.register("table", function(table) {
	if ("no_en".hasClass(table)) return false;
	var bs = table.tBodies;
	for (var i = 0; i < bs.length; i++) {
		var rows = bs[i].rows;
		for (var r = 1, n = rows.length; r < n; r+=2)
			rows[r].className += ' odd';
	}
});



Yutil.en.register("ul.nav", function(ul) {
	var lis = ul.getElementsByTagName("li");
	for (var i = 0; i < lis.length; i++) {
		var li = lis[i];
		if (li.parentNode != ul && li.getElementsByTagName("ul").length > 0)
			"daddy".addClass("a".resolveFirst(li));
		li.onmouseover = function() { "nav_hover".addClass(this) };
		li.onmouseout = function() { "nav_hover".removeClass(this) };
	}
});

Yutil.quick_sel = {
	ee:'',
	enhance:function(elem) {
		ee = elem.id;
		var theFieldset = elem;
		var theLegend = theFieldset.getElementsByTagName('legend')[0];
		var hasLink = false;
		if(theLegend.getElementsByTagName('a') == null)
			hasLink = false;
		
		var newLink; 
		if(hasLink == false) {
			newLink = ("<a href='javascript:;'>Manage all</a>").createElement();
			//manageAll 
			Event.observe(newLink, 'click', Yutil.quick_sel.act); //this.act
			theLegend.appendChild(newLink);
			//theLegend.insertBefore(newLink, theLegend.firstChild);
		} else {
			return;
		}
	},
	act: function() {
			var elemId = ee;
			var dialogName = '_' + elemId + '_Dialog';
			Yutil.createDialog(dialogName, '80%', '80%', 'Manage all');
			
			var url = 'd' + '_' + elemId + '_Dialog.jsp';
			var myAjax = new Ajax.Updater(dialogName + '_content', url, {method:'get',  evalScripts: true});
			Yutil.showDialog(dialogName);
	}
}

testManage = function() {
	alert('2122112');
}

Yutil.en.register('fieldset.quick_sel',Yutil.quick_sel.enhance);

Yutil.toolong = {
	re: /^(\d+)em$/,
	
	enhance: function(t) {
		var txt = Yutil.innerText(t).trim();
		var bits = Yutil.toolong.re.exec(t.style.width);
		if (!bits) {alert("style='width:xxem' is required on 'toolong' element"); return false;}
		
		var size = parseInt(bits[1]) * 1.5 - 2;
		var len, c;
		for (len = 0; len < txt.length && size > 0; len++) {
			c = txt.charAt(len);
			if ("ijlrI ,.!()-/\|[]'\":;".indexOf(c) >= 0)
				size -= .5;
			else if ("wmWM".indexOf(c) >= 0)
				size -= 1.5;
			else if ('A' <= c && c <= 'Z')
				size -= 1.2;
			else
				size -= 1;
		}
		if (len == txt.length) return false;

		t.brief = txt.substring(0, len);
		t.full = txt;
		Event.observe(t, 'dblclick', Yutil.toolong.toggle);
		Yutil.toolong.toBrief(t);
	},
	
	toggle: function(event) {
		var t = event.target || event.srcElement;
		if (t.innerHTML.indexOf(">...<") > 0)
			Yutil.toolong.toFull(t);
		else
			Yutil.toolong.toBrief(t);
		if (document.selection) document.selection.empty();
	},
	
	toBrief: function(t) {
		t.title = t.full;
		t.innerHTML = t.brief + " <a href='javascript:;' onclick='Yutil.toolong.toFull(this.parentNode)'>...</a>";
	},
	
	toFull: function(t) {
		t.title = '';
		t.innerHTML = t.full + " <a href='javascript:;' onclick='Yutil.toolong.toBrief(this.parentNode)'>&lt;&lt;</a>";
	}
}
Yutil.en.register("div.toolong", Yutil.toolong.enhance);

Yutil.foldable = {
	enhance: function(elem) {
		// identify content
		elem.content = $(elem.getAttribute('rel'));
		if (!elem.content)
			elem.content = '+*'.resolveFirst(elem);
		
		// init looking
		Yutil.foldable.toggle(elem, elem.content.style.display != 'none');
		
		// listen event
		Event.observe(elem, 'click', Yutil.foldable.onClick);
	},
	
	onClick: function(event) {
		var elem = event.target || event.srcElement;
		while (elem != null && !"span".isTagOf(elem) || !"foldable".hasClass(elem))
			elem = "span".ascendantOf(elem);
		if (elem && !"disabled".hasClass(elem))
			Yutil.foldable.toggle(elem);
	},
	
	toggle: function(elem, toOpen) {
		elem = $(elem);
		if (toOpen == null)
			toOpen = elem.content.style.display == 'none';
		if (toOpen)
			Yutil.foldable.open(elem);
		else
			Yutil.foldable.close(elem);
	},
	
	open: function(elem) {
		elem = $(elem);
		'foldable_close'.removeClass(elem);
		'foldable_open'.addClass(elem);
		elem.content.style.display = ''; // '' works better than 'block'
	},
	
	close: function(elem) {
		elem = $(elem);
		'foldable_open'.removeClass(elem);
		'foldable_close'.addClass(elem);
		elem.content.style.display = 'none';
	}
}
Yutil.en.register('span.foldable', Yutil.foldable.enhance);

Yutil.tree = {
	openImage: 'web/images/icon-tree-open.gif',
	closeImage: 'web/images/icon-tree-close.gif',
	
	enhance: function(elem) {
		var li = elem.getElementsByTagName('li');
		for (var i = 0; i < li.length; i++) {
			var node = 'span'.resolveFirst(li[i]);
			var child = 'ul'.resolveFirst(li[i]);
			if (!node || !child) {
				'tree_leaf'.addClass(li[i]);
				continue;
			}
			'tree_node'.addClass(node);
			var img = ("<img src='" + (child.style.display == 'none' ? Yutil.tree.closeImage : Yutil.tree.openImage) + "' class='tree_img'/>").createElement();
			node.insertBefore(img, node.firstChild);
			Event.observe(node, 'click', Yutil.tree.toggle);
		}
	},

	toggle: function(event) {
		var evtElem = event.target || event.srcElement;
		if(evtElem.className == 'tree_img'){
			var cid = 'a'.resolveFirst(evtElem.parentNode);
			if(!cid){
				var span = 'span'.resolveFirst(evtElem.parentNode);
				if(span) cid = 'a'.resolveFirst(span);
			}
			//if(!cid) return;
			
			var open = Yutil.tree.toggleElem(evtElem);
			if(open){
				NodeRem.add(cid);
			}else{
				NodeRem.removeTree(cid);
			}
		}
	},
	
	toggleElem: function(evtElem){
		var li = 'li'.ascendantOf(evtElem);
		var img = 'span'.resolveFirst(li).firstChild;
		var child = 'ul'.resolveFirst(li);
		var open = evtElem == img ? child && child.style.display == 'none' : true;
		if (open) {
			img.src = Yutil.tree.openImage;
			if(child)
				child.style.display = 'block';
			return true;
		} else {
			img.src = Yutil.tree.closeImage;
			if(child)
				child.style.display = 'none';
			return false;
		}
	}
}
Yutil.en.register('ul.tree', Yutil.tree.enhance);

Yutil.tabs = {
	enhance: function(elem) {
		if(!$('sepElem')) {
			var sep = '<div class="sep" id="sepElem">&nbsp;</div>'.createElement();
			elem.insertBefore(sep, null);
		}
		var tabs = '/a'.resolve(elem);
		var cur = tabs[0], tab;
		for (var i = 0; i < tabs.length; i++) {
			tab = tabs[i];
			if ('act'.hasClass(tab))
				cur = tab;
			Event.observe(tab, 'click', Yutil.tabs.onTabClick);
		}
		Yutil.tabs.focus(cur);
	},
	
	onTabClick: function(event) {
		Yutil.tabs.focus(event.target || event.srcElement);
	},
	
	focus: function(curTab) {
		var tabs = '../a'.resolve(curTab);
		for (var i = 0; i < tabs.length; i++) {
			var t = tabs[i].rel && $(tabs[i].rel);
			if (tabs[i] == curTab) {
				'act'.addClass(tabs[i]);
				if (t) t.style.display = 'block';
			} else {
				'act'.removeClass(tabs[i]);
				if (t) t.style.display = 'none';
			}
		}
		if (window.Yfit) Yfit.makeFit(document);
	}
}
Yutil.en.register('div.tabs', Yutil.tabs.enhance);

Yutil.roundcorner = {
	enhance: function(e) {
		var cls = 'rcn', n = 4, bg = 'transparent', top = true, bottom = true;
		var attr = ' ' + e.getAttribute('roundcorner');
		if (attr.indexOf('small') > 0)	{ cls = 'rcs'; n = 2; }
		if (attr.indexOf('big') > 0)	{ cls = 'rcb'; n = 8; }
		if (attr.indexOf('top') > 0)	bottom = false;
		if (attr.indexOf('bottom') > 0)	top = false;
		
		// determine background
		var p = e.parentNode;
		while (p != document && bg == 'transparent') {
			bg = Element.getStyle(p, 'background-color');
			p = p.parentNode;
		}
		if (bg == 'transparent') bg = '#FFF';
		
		// add round corner
		if (top)
			e.insertBefore(Yutil.roundcorner._var(cls, n, bg, true), e.firstChild);
		if (bottom)
			e.insertBefore(Yutil.roundcorner._var(cls, n, bg, false), null);
	},
	
	_var: function(cls, n, bg, top) {
		var r = "<var class='roundcorner'>", j;
		for (var i = 1; i <= n; i++) {
			j = top ? i : (n - i + 1);
			r += "<var class='"+cls+j+"' style='border-color:"+bg+"'></var>";
		}
		r += "</var>";
		return r.createElement();
	}
}
Yutil.en.register('div.roundcorner', Yutil.roundcorner.enhance);

String.prototype.splitExcludeBlank = function(regex) {
	var out = this.split(regex);
	if (out.indexOf('') < 0) return out;
	var r = [];
	for (var i = 0; i < out.length; i++)
		if (out[i].length > 0)
			r.push(out[i]);
	return r;
}

String.prototype.isTagOf = function(node) {
	if (node && node.tagName && node.tagName.toLowerCase() == this.toLowerCase())
		return true;
	else
		return false;
}

String.prototype.trim = function() {
	return this.replace(/^\s+|\s+$/g, "");
}

String.prototype.trimAfter = function(t) {
	var i = this.indexOf(t);
	return i < 0 ? this.toString() : this.substring(0, i);
}

String.prototype.evalScripts = function() {
	var r = new RegExp('<script[^>]*>([\\s\\S]*?)</script>', 'img'), m;
	while (m = r.exec(this)) {
		try {
		eval(m[1]);
		} catch (e) {
			console.debug(m[1]);
			console.debug(e);
		}
	}
}

String.prototype.createElement = function() {
	return jQuery.clean([this.toString()])[0];
}

String.prototype.enclosing = function(node, limit) {
	while (!this.isTagOf(node) && node != null && node != limit)
		node = node.parentNode;
	return node == limit ? null : node;
}

String.prototype.ascendantOf = function(elem, limit) {
	if (!elem) return null;
	return Yutil._findTagByProperty(elem, this, "parentNode", limit);
}

String.prototype.descendantsOf = function(elem) {
	if (!elem) return [];
	return elem.getElementsByTagName(this);
}

String.prototype.previousOf = function(elem, limit) {
	if (!elem) return null;
	return Yutil._findTagByProperty(elem, this, "previousSibling", limit);
}

String.prototype.nextOf = function(elem, limit) {
	if (!elem) return null;
	return Yutil._findTagByProperty(elem, this, "nextSibling", limit);
}

Yutil._findTagByProperty = function(elem, tag, prop, limit) {
	elem = elem[prop];
	if (tag) {
		while (elem != null && elem != limit && !tag.isTagOf(elem))
			elem = elem[prop];
	} else {
		while (elem != null && elem != limit && elem.nodeType != 1)
			elem = elem[prop];
	}
	return elem;
}

String.prototype.addClass = function(elem) {
	if (!this.hasClass(elem))
		elem.className = elem.className + ' ' + this;
}

String.prototype.removeClass = function(elem) {
	elem.className = elem.className.replace(new RegExp('(^|\\s)' + this + '\\b'), '');
}

String.prototype.hasClass = function(elem) {
	return new RegExp('\\b' + this + '\\b').test(elem.className) ? this : '';
}

String.prototype.resolveFirst = function(root) {
	return this.resolve(root)[0];
}

String.prototype.resolve = function(root) {
	var ptn = this;
	if (ptn.search(/\/|\+|-/) != 0)
		ptn = '/' + ptn;
	var result = [root];
	var regex = /(\/|\+|-)(\.\.|\*|\w*\.?\w+)/g;
	var found;
	while (found = regex.exec(ptn)) {
		var tmp = [];
		for (var i = 0; i < result.length; i++) {
			string_resolve_collect(result[i], found[1], found[2], tmp);
		}
		result = tmp;
	}
	return result;
}

function string_resolve_collect(elem, op, cond, result) {
	if ('..' == cond)
		return result.push(elem.parentNode);
	
	if ('/' == op) {
		for (var n = elem.firstChild; n != null; n = n.nextSibling)
			if (n.nodeType == 1 && string_resolve_validate(n, cond))
				result.push(n);
	} else if ('+' == op) {
		for (var n = elem.nextSibling; n != null; n = n.nextSibling)
			if (n.nodeType == 1 && string_resolve_validate(n, cond))
				result.push(n);
	} else if ('-' == op) {
		for (var n = elem.previousSibling; n != null; n = n.previousSibling)
			if (n.nodeType == 1 && string_resolve_validate(n, cond))
				result.push(n);
	}
}

function string_resolve_validate(elem, cond) {
	if ('*' == cond)
		return true;
	var tac = cond.split('.');
	if (tac[0] && tac[0] != elem.tagName.toLowerCase())
		return false;
	if (tac[1] && !tac[1].hasClass(elem))
		return false;
	return true;
}

String.prototype.setCookie = function(value, days) {
	if (days) {
		var date = new Date();
		date.setTime(date.getTime()+(days*24*60*60*1000));
		var expires = "; expires="+date.toGMTString();
	}
	else var expires = "";
	document.cookie = this+"="+escape(value)+expires+"; path=/";
}

String.prototype.getCookie = function() {
	var nameEQ = this + "=";
	var c = document.cookie;
	var s = c.indexOf(nameEQ);
	if (s >= 0) {
		var e = c.indexOf(";", s);
		return unescape(c.substring(s, e >= 0 ? e : c.length));
	}
	return null;
}

String.prototype.delCookie = function() {
	this.setCookie("",-1);
}


Array.prototype.retain = function(arr) {
	var r = [];
	for (var i = 0; i < arr.length; i++) {
		if (this.indexOf(arr[i]) >= 0)
			r.push(arr[i]);
	}
	return r;
}



// fireEvent() for non-IE agents
if (!document.fireEvent) {

Element.prototype.fireEvent = function(type) {
type = (type.substring(0,2) == 'on') ? type.substr(2) : type;
var eventObject;
switch (type) {
case 'DOMActivate':
case 'DOMFocusIn':
case 'DOMFocusOut':
// UIEvent
eventObject = this.ownerDocument.createEvent('UIEvents');
eventObject.initUIEvent(type, true, true, this.ownerDocument.defaultView, 1);
break;

case 'click':
case 'mousedown':
case 'mousemove':
case 'mouseout':
case 'mouseover':
case 'mouseup':
case 'contextmenu': // proprietary Gecko event
// MouseEvent
eventObject = this.ownerDocument.createEvent('MouseEvents');
var box = this.ownerDocument.getBoxObjectFor(this.ownerDocument.body);
eventObject.initMouseEvent(type, true, true, this.ownerDocument.defaultView, 1, box.screenX, box.screenY, 0, 0, false, false, false, false, 0, this);
break;

case 'keydown':
case 'keypress':
case 'keyup':
// Gecko-only KeyEvent - to be replaced by TextEvent in DOM3 Events
eventObject = this.ownerDocument.createEvent('KeyEvents');
eventObject.initKeyEvent(type, true, true, this.ownerDocument.defaultView, false, false, false, false, 0, 0);
break;

case 'DOMAttrModified':
case 'DOMCharacterDataModified':
case 'DOMNodeInserted':
case 'DOMNodeInsertedIntoDocument':
case 'DOMNodeRemoved':
case 'DOMNodeRemovedFromDocument':
case 'DOMSubtreeModified':
// MutationEvent
eventObject = this.ownerDocument.createEvent('MutationEvents');
eventObject.initMutationEvent(type, true, false, this, null, null, null, MutationEvent.MODIFICATION);
break;

case 'abort':
case 'blur':
case 'change':
case 'error':
case 'focus':
case 'load':
case 'reset':
case 'resize':
case 'select':
case 'scroll':
case 'submit':
case 'unload':
// HTMLEvent
eventObject = this.ownerDocument.createEvent('HTMLEvents');
eventObject.initEvent(type, true, true);
break;

default:
// CustomEvent
eventObject = this.ownerDocument.createEvent('Events');
eventObject.initEvent(type, true, true);
}
this.dispatchEvent(eventObject);
}

}
// end fireEvent

// A common handler before page unload
Yutil.beforeUnload = function() {
	if (window.NOT_UNLOAD) { window.NOT_UNLOAD = false; return; } // fix stupid IE

	var msg = "";

	if ($('_changes') && $('_changes').isChanged) {
		// popup confirm dialog before unload
		try {
			window.event.returnValue = msg; // the IE way
		} catch(e) {
			return msg; // the FF way
		}
	}
}

Yutil.hasChanges = function(){
	if(!$('_changes') || !$('_changes').isChanged)
		return false;
	return true;
}

Yutil.chgDetect = function(targetId){
	if(!$('_changes') || !$('_changes').isChanged)
		return true;
	
	//Note: currentFocus may change from a button to a popup dialog when clicking a button, and pops up a dialog
	var curFocus = Yutil.currentFocus();
	window.NOT_UNLOAD = true;

	//No check for a popup dialog
	if(DwcUtil.hasParentClass(curFocus, 'dialog')) {
		return true;
	}

	//changes happen and the link is not in the edit area, here assume content_right is the edit area
	if($('_changes') && $('_changes').isChanged &&  ($('content_right') && !DwcUtil.isChildOf(curFocus,$('content_right')) || !$('content_right') &&  !DwcUtil.isChildOf(curFocus,$('content')))){
		if (!window.confirm('Are you sure you want to navigate away from this page? Press OK to continue, or Cancel to stay on the current page. ')){
			//stay on the current page
			return false;
		}
		//Clear change if you select OK to leave the page
		Yutil.clearChange();
	}
	
	//link/button in the edit area
	if($('content_right')&& DwcUtil.isChildOf(curFocus,$('content_right')) || !$('content_right') && DwcUtil.isChildOf(curFocus,$('content'))){
		var label = Yutil.innerText(curFocus);
		var target = $(targetId);
		//The link/button in edit area is rewritten by a father target
		if($('_changes') && $('_changes').isChanged &&  target && DwcUtil.isChildOf(curFocus,target)){
			if (!window.confirm('Are you sure you want to navigate away from this page? Press OK to continue, or Cancel to stay on the current page. ')){
				//stay on the current page
				return false;
			}
			Yutil.clearChange();
		}
	}
	
	//For save/cancel/back/create button
	if(curFocus && label){
		label = label.toUpperCase();
		if(label.indexOf('SAVE') > -1 || label.indexOf('CANCEL') > -1 || label.indexOf('BACK') > -1 || label.indexOf('CREATE') > -1 || label.indexOf('RESET') > -1 || label.indexOf('REFRESH') > -1){
			Yutil.clearChange();
		}
	}

	return true;
}

Yutil.clearChange = function(){
	if($('_changes')){
		$('_changes').isChanged=false;
	}
}

/**
 * Force the change flag to true; Used when the table content is not changed, but you want the change flag to be true
 * Use this carefully, as it's kind of dirty trick.
 */
Yutil.forceChange=function(){
	if(!$('_changes')){
		var _changes = ("<div id='_changes' class='hidden'></div>").createElement();
		document.body.appendChild(_changes);
	}
	$('_changes').isChanged = true;
}

//Trick for stupid IE which fires onbeforeunload whenever a <a> element is clicked
if (window.attachEvent) {
	document.attachEvent('onclick', function() {
		// IE triggers onbeforeunload on any <a> click, even it's just javascript
		var a = window.event.srcElement;
		if (a.href && 'javascript:'==a.href.substring(0, 11)){
		    window.NOT_UNLOAD = true;
		}
    });
}
